package com.colter.project.sample.thread.part04.test1;

import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Test8 {
	public static void main(String[] args) {
		ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
		CompletionService<String> service = new ExecutorCompletionService<>(executor);

		ReportRequest faceRequest = new ReportRequest("Face", service);
		ReportRequest webRequest = new ReportRequest("Web", service);
		Thread faceThread = new Thread(faceRequest);
		Thread webThread = new Thread(webRequest);
		ReportProcessor processor = new ReportProcessor(service, false);

		Thread sendThread = new Thread(processor);
		System.out.println("Main: start the thread.");
		faceThread.start();
		webThread.start();
		sendThread.start();

		try {
			System.out.println("Main: waiting for the report generators");
			faceThread.join();
			webThread.join();
		} catch (Exception e) {
			// TODO: handle exception
		}

		System.out.println("Main: shutting down executor.");
		executor.shutdown();

		try {
			executor.awaitTermination(30, TimeUnit.SECONDS);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		processor.setEnd(true);
		System.out.println("Main: end");
	}
}

class ReportGenerator implements Callable<String> {

	private String sender;
	private String title;

	public ReportGenerator(String sender, String title) {
		super();
		this.sender = sender;
		this.title = title;
	}

	@Override
	public String call() throws Exception {
		try {
			long duration = (long) (Math.random() * 10);
			System.out.println(sender + "-" + title + "Generating a report during " + duration);
			TimeUnit.SECONDS.sleep(duration);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return sender + ":" + title;
	}

}

class ReportRequest implements Runnable {
	private String name;

	private CompletionService<String> service;

	public ReportRequest(String name, CompletionService<String> service) {
		super();
		this.name = name;
		this.service = service;
	}

	@Override
	public void run() {
		ReportGenerator reportGenerator = new ReportGenerator(name, "Report");
		service.submit(reportGenerator);
	}
}

class ReportProcessor implements Runnable {
	private CompletionService<String> service;

	private boolean end;

	public ReportProcessor(CompletionService<String> service, boolean end) {
		super();
		this.service = service;
		this.end = end;
	}

	@Override
	public void run() {
		while (!end) {
			try {
				Future<String> result = service.poll(20, TimeUnit.SECONDS);
				if (result != null) {
					String report = result.get();
					System.out.println("Report Receiver: Report received:" + report);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		System.out.println("Report Processor: End");

	}

	public void setEnd(boolean end) {
		this.end = end;
	}

}
